#include "StdAfx.h"
#include "TaskManager.hpp"

HpsFramework::Tasks::TaskManager::TaskManager( void )
{
	this->_queue = CreateTimerQueue();
}

HpsFramework::Tasks::TaskManager::~TaskManager( void )
{
	DeleteTimerQueueEx ( this->_queue, INVALID_HANDLE_VALUE );

	LockList(&this->_taskList)

		StartListIteration(TaskInformation*, &this->_taskList)
		{
			TaskInformation* info = CurrentNode->getContent();
			CurrentNode = GetNextNode();
			delete info;
		}
		FinishListIteration();

	UnlockList();
}

void HpsFramework::Tasks::TaskManager::releaseTask( TaskId id )
{

	LockList(&this->_taskList)

		StartListIteration(TaskInformation*, &this->_taskList)
		{
			if(CurrentNode->getContent()->id == id)
			{
				TaskInformation* task = CurrentNode->getContent();
				DeleteTimerQueueTimer ( this->_queue, task->handle, INVALID_HANDLE_VALUE );
				GetContainer()->remove(CurrentNode);
				delete task;
			}
			CurrentNode = GetNextNode();
		}
		FinishListIteration();

	UnlockList();

}

HpsFramework::Tasks::TaskId HpsFramework::Tasks::TaskManager::registerTask( TaskFunction function, TaskInterval interval /*= ExecuteTaskOnce*/, TaskParameter parameter /*= InvalidTaskParameter*/, TaskInterval delayBeforeStart /*= 0*/, bool overl /*= false*/, bool heavytask /*= false */ )
{

	TaskInformation* info = new TaskInformation();

	info->id = this->_taskIds.getKey();
	info->type = TTypeFunction;
	info->interval = interval;
	info->delay = delayBeforeStart;
	info->parameter = parameter;
	info->function = function;
	info->object = NULL;
	info->overlap = overl;
	info->once = false;

	ULONG flags = heavytask ? WT_EXECUTELONGFUNCTION : WT_EXECUTEINTIMERTHREAD;
	if(info->interval == ExecuteTaskOnce)
	{
		flags |= WT_EXECUTEONLYONCE;
		info->interval = 0;
		info->once = true;
	}

	if ( ! CreateTimerQueueTimer ( &info->handle, this->_queue, TaskManager::TaskCallback, (PVOID)info, info->delay, info->interval, flags ) )
	{
		delete info;
		return InvalidTaskId;
	}

	if((flags & WT_EXECUTEONLYONCE) == WT_EXECUTEONLYONCE)
	{
		return InvalidTaskId;
	}
	else
	{
		this->_taskList.addLast ( info );
	}

	return info->id;
}

HpsFramework::Tasks::TaskId HpsFramework::Tasks::TaskManager::registerTask( TaskObject* object, TaskInterval interval /*= ExecuteTaskOnce*/, TaskParameter parameter /*= InvalidTaskParameter*/, TaskInterval delayBeforeStart /*= 0*/, bool overl /*= false*/, bool heavytask /*= false */ )
{
	TaskInformation* info = new TaskInformation();

	info->id = this->_taskIds.getKey();
	info->type = TTypeObject;
	info->interval = interval;
	info->delay = delayBeforeStart;
	info->parameter = parameter;
	info->function = NULL;
	info->object = object;
	info->overlap = overl;
	info->once = false;

	ULONG flags = heavytask ? WT_EXECUTELONGFUNCTION : WT_EXECUTEINTIMERTHREAD;
	if(info->interval == ExecuteTaskOnce)
	{
		flags |= WT_EXECUTEONLYONCE;
		info->interval = 0;
		info->once = true;
	}

	if ( ! CreateTimerQueueTimer ( &info->handle, this->_queue, TaskManager::TaskCallback, (PVOID)info, info->delay, info->interval, flags ) )
	{
		delete info;
		return InvalidTaskId;
	}

	if((flags & WT_EXECUTEONLYONCE) == WT_EXECUTEONLYONCE)
	{
		return InvalidTaskId;
	}
	else
	{
		this->_taskList.addLast ( info );
	}

	return info->id;
}

void __stdcall HpsFramework::Tasks::TaskManager::TaskCallback( void* param, unsigned char toef )
{
	TaskInformation* info = (TaskInformation*)param;
	if(info)
	{

		if(!info->overlap && info->running)
		{
			return;
		}

		switch(info->type)
		{
		case TTypeFunction:
			{
				info->running = true;
				if(!info->function ( info->parameter ) && !info->once)
				{
					TaskManager::getInstance()->releaseTask(info->id);
					return;
				}
				info->running = false;
				if(info->once) {
					delete info;
				}
			}
			break;

		case TTypeObject:
			{
				info->running = true;
				if(!info->object->executeTask ( info->parameter ) && !info->once)
				{
					TaskManager::getInstance()->releaseTask(info->id);
					return;
				}
				info->running = false;
				if(info->once) {
					delete info;
				}
			}
			break;

		}

	}
}
